package cn.jbolt.core.util;

import com.jfinal.aop.Aop;
import org.checkerframework.checker.units.qual.C;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class JBoltMethodCaller {

    /**
     * method映射
     */
    private static final ConcurrentHashMap<String, Object> METHODS = new ConcurrentHashMap<>();

    /**
     * 类的实例
     */
    private static final ConcurrentHashMap<String, Object> INSTANCES = new ConcurrentHashMap<>();


    /**
     * 调用某个类的某个方法
     *
     * @param classPath
     * @param methodName
     * @param argTypes
     * @param args
     * @param <T>
     * @return
     */
    public static <T> T call(String classPath, String methodName, Class[] argTypes, Object[] args) throws Exception {
        String key = classPath + "_" + methodName;
        if (argTypes != null) {
            for (Class argType : argTypes) {
                key += "_" + argType.getSimpleName();
            }
        }

        Object instance = INSTANCES.get(classPath);
        if (instance == null) {
            instance = resolveInstance(classPath);
        }
        if (Objects.equals(instance, false)) {
            //如果key 绑定了false，表明这个类的实例不存在
            throw new RuntimeException(classPath + "无法实例化");
        }


        Object value = METHODS.get(key);

        if (value == null) {
            value = resolveMethod(key, classPath, methodName, argTypes);
        }
        if (Objects.equals(value, false)) {
            //如果key 绑定了false，表明这个方法不存在，或无法调用
            throw new RuntimeException(classPath + "." + methodName + "无法调用");
        }



        Method method = (Method) value;


        return (T) method.invoke(instance, args);
    }


    private static Object resolveInstance(String classPath) {
        try {


            Class<?> clazz = Class.forName(classPath);

            Object instance = Aop.get(clazz);
            if (instance == null) {
                throw new RuntimeException(classPath + "类的实例无法获取");
            }

            INSTANCES.putIfAbsent(classPath, instance);
            return instance;
        } catch (Exception e) {
            e.printStackTrace();
            INSTANCES.put(classPath, false);
            return false;
        }
    }

    /**
     * 解析方法
     *
     * @param key
     * @param classPath
     * @param methodName
     * @param argTypes
     * @return
     */
    private static Object resolveMethod(String key, String classPath, String methodName, Class[] argTypes) {
        try {


            Class<?> clazz = Class.forName(classPath);


            Method method = clazz.getMethod(methodName, argTypes);
            METHODS.putIfAbsent(key, method);
            return method;
        } catch (Exception e) {
            e.printStackTrace();
            METHODS.put(key, false);
            return false;
        }
    }

    public static void main(String[] args) {
        System.out.println(String.class.getSimpleName());
    }
}
